#ifndef __CROSSFIRE_ANIMMESH
#define __CROSSFIRE_ANIMMESH

#define DELETE_POINTER(p) { if(p) { delete (p);   (p)=NULL; } }
#define DELETE_ARRAY(p) { if(p) { delete[] (p);   (p)=NULL; } }
#define RELEASE_POINTER(p)  { if(p) { (p)->Release(); (p)=NULL; } }

struct D3DXFRAME_DERIVED: public D3DXFRAME
{
  D3DXMATRIXA16 CombinedTransformationMatrix;
};

struct D3DXMESHCONTAINER_DERIVED: public D3DXMESHCONTAINER
{
  LPDIRECT3DTEXTURE9*  ppTextures;       // array of textures, entries are NULL if no texture specified    

  // SkinMesh info             
  LPD3DXMESH           pOrigMesh;
  LPD3DXATTRIBUTERANGE pAttributeTable;
  DWORD                NumAttributeGroups; 
  DWORD                NumInfl;
  LPD3DXBUFFER         pBoneCombinationBuf;
  D3DXMATRIX**         ppBoneMatrixPtrs;
  D3DXMATRIX*          pBoneOffsetMatrices;
  DWORD                NumPaletteEntries;
  bool                 UseSoftwareVP;
  DWORD                iAttributeSW;     
};


class CAllocateHierarchy : public ID3DXAllocateHierarchy
{
private:
  HRESULT AllocateName( LPCSTR Name, LPSTR *pNewName );

public:
  CAllocateHierarchy(void);
  ~CAllocateHierarchy(void);

  HRESULT GenerateSkinnedMesh( LPDIRECT3DDEVICE9 pd3dDevice, D3DXMESHCONTAINER_DERIVED *pMeshContainer );

  STDMETHOD(CreateFrame)(THIS_ LPCSTR Name, LPD3DXFRAME *ppNewFrame);
  STDMETHOD(CreateMeshContainer)(THIS_ LPCSTR Name, CONST D3DXMESHDATA *pMeshData,
    CONST D3DXMATERIAL *pMaterials, CONST D3DXEFFECTINSTANCE *pEffectInstances, 
    DWORD NumMaterials, CONST DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo, 
    LPD3DXMESHCONTAINER *ppNewMeshContainer);

  STDMETHOD(DestroyFrame)(THIS_ LPD3DXFRAME pFrameToFree);
  STDMETHOD(DestroyMeshContainer)(THIS_ LPD3DXMESHCONTAINER pMeshContainerBase);
};


class CCF_AnimMesh
{
private:
  LPD3DXFRAME m_rootFrame;
  LPD3DXANIMATIONCONTROLLER m_animController;
  LPDIRECT3DDEVICE9 m_device;
  CAllocateHierarchy* m_allocHierarchy;


  HRESULT SetupBoneMatrixPointers( LPD3DXFRAME pFrame );
  HRESULT SetupBoneMatrixPointersOnMesh( LPD3DXMESHCONTAINER pMeshContainerBase );
  void DrawMeshContainer( IDirect3DDevice9 *pd3dDevice, LPD3DXMESHCONTAINER pMeshContainerBase, LPD3DXFRAME pFrameBase );
  void DrawFrame( IDirect3DDevice9 *pd3dDevice, LPD3DXFRAME pFrame );
  void UpdateFrameMatrices( LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix );
  void UpdateSkinningMethod( LPD3DXFRAME pFrameBase );

public:
	 

  CCF_AnimMesh(void);
  ~CCF_AnimMesh(void);
  void Initialize( LPDIRECT3DDEVICE9 device, LPWSTR filename );
  void Draw();
  void Update();
  void UpdateAnimation( double delta );

};

#endif